/* Transform cfg to gml.

   Copyright (C) 2009, 2010 Mingjie Xing, mingjie.xing@gmail.com. 

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <unistd.h>
#include <error.h>
#include <obstack.h>

#include <argp.h>

#include "gcctree2gml.h"


/* Concatenate an arbitrary number of strings.  You must pass NULL as
   the last argument of this function, to terminate the list of
   strings.  Allocates memory using xmalloc.  */

extern char *concat (const char *, ...);

extern char *fin_name;
extern char *fout_name;


void
cfg_to_gml (void)
{
  struct control_flow_graph *cfg;
  struct basic_block *bb;
  struct edge *e;
  int entryid = 0;
  int exitid = 0;
  char *newf = NULL;
  size_t lnewf = 0;
  FILE *fo = NULL;
  int nnodes = 0;
  int nedges = 0;

  fprintf (fout,
	   "# generated by gcctree2gml from %s\ngraph [\n  directed 1\n",
	   fin_name);

  /* top graph */

  for (current_function = first_function; current_function != NULL;
       current_function = current_function->next)
    {
      /* create new sub-file */
      lnewf =
	strlen (fout_name) + strlen ("-") + strlen (current_function->name) +
	strlen (".gml");
      newf = malloc (lnewf + 1);
      memset (newf, 0, lnewf + 1);
      strcat (newf, fout_name);
      strcat (newf, "-");
      strcat (newf, current_function->name);
      strcat (newf, ".gml");
      fo = fopen (newf, "w");
      nnodes = 0;
      nedges = 0;

      fprintf (fo,
	       "# generated by gcctree2gml from %s for function %s()\ngraph [\n  directed 1\n",
	       fin_name, current_function->name);

      cfg = current_function->cfg;

      uid++;
      entryid = uid;

      fprintf (fout, "  node [ id %d label \"%s()\nENTRY\" ]\n", entryid,
	       current_function->name);

      fprintf (fo, "  node [ id %d label \"%s()\nENTRY\" ]\n", entryid,
	       current_function->name);
      nnodes++;

      uid++;
      exitid = uid;

      fprintf (fout, "  node [ id %d label \"%s()\nEXIT\" ]\n", exitid,
	       current_function->name);

      fprintf (fo, "  node [ id %d label \"%s()\nEXIT\" ]\n", exitid,
	       current_function->name);
      nnodes++;

      for (bb = cfg->bb; bb != NULL; bb = bb->next)
	{
	  /* bb graph */
	  if (strcmp (bb->name, "ENTRY") == 0)
	    {
	      /* bb1 is entry node */
	      continue;
	    }
	  if (strcmp (bb->name, "EXIT") == 0)
	    {
	      /* bb2 is exit node */
	      continue;
	    }

	  if (1)
	    {
	      fprintf (fout,
		       "  node [ id %d label \"<bb %s>: %s()\n%s\n\" ]\n",
		       bb->id, bb->name, current_function->name, bb->text);

	      fprintf (fo,
		       "  node [ id %d label \"<bb %s>: %s()\n%s\n\" ]\n",
		       bb->id, bb->name, current_function->name, bb->text);
	      nnodes++;
	    }
	  else
	    {
	      fprintf (fout, "  node [ id %d ]\n", bb->id);

	      fprintf (fo, "  node [ id %d ]\n", bb->id);
	      nnodes++;
	    }
	}


      for (e = cfg->edge; e != NULL; e = e->next)
	{
	  if (strcmp (e->source->name, "ENTRY") == 0)
	    {
	      fprintf (fout, "  edge [ source %d target %d ]\n", entryid,
		       e->target->id);

	      fprintf (fo, "  edge [ source %d target %d ]\n", entryid,
		       e->target->id);
	      nedges++;
	    }
	  else if (strcmp (e->target->name, "EXIT") == 0)
	    {
	      fprintf (fout, "  edge [ source %d target %d ]\n",
		       e->source->id, exitid);

	      fprintf (fo, "  edge [ source %d target %d ]\n",
		       e->source->id, exitid);
	      nedges++;
	    }
	  else
	    {
	      fprintf (fout, "  edge [ source %d target %d ", e->source->id,
		       e->target->id);

	      fprintf (fo, "  edge [ source %d target %d ", e->source->id,
		       e->target->id);
	      nedges++;

	      if (e->type == RETREATING_EDGE)
		{
		  /* blue line color */
		  fprintf (fout, "graphics [ fill \"#0000ff\" ] ");

		  fprintf (fo, "graphics [ fill \"#0000ff\" ] ");
		}
	      fprintf (fout, "]\n");
	      fprintf (fo, "]\n");
	    }


	}

      fprintf (fo, "]\n# %d nodes and %d edges", nnodes, nedges);
      fclose (fo);
      free (newf);
      newf = NULL;
      lnewf = 0;

    }

  fprintf (fout, "]\n");

  return;
}
